/**
  @file
  Display the ACPI tables

  Copyright (c) 2011-2012, Intel Corporation. All rights reserved.
  SPDX-License-Identifier: BSD-2-Clause-Patent

**/

#include <WebServer.h>
#include <Guid/Acpi.h>
#include <IndustryStandard/Acpi10.h>
#include <IndustryStandard/Acpi30.h>

#if defined(_MSC_VER)   //  Handle Microsoft VC++ compiler specifics.
#pragma warning ( disable : 4305 )
#endif  //  defined(_MSC_VER)

//
// Ensure proper structure formats
//
#pragma pack(1)

typedef struct {
  UINT8 AddressSpaceId;
  UINT8 RegisterBitWidth;
  UINT8 RegisterBitOffset;
  UINT8 AccessSize;
  UINT64 Address;
} GENERIC_ADDRESS;


typedef struct {
  UINT32 Signature;           //    0
  UINT32 Length;              //    4
  UINT8 Revision;             //    8
  UINT8 Checksum;             //    9
  UINT8 OemId[6];             //   10
  UINT8 OemTableId[8];        //   16
  UINT32 OemRevision;         //   24
  UINT32 CreatorId;           //   28
  UINT32 CreatorRevision;     //   32
  UINT8 DefinitionBlock[1];   //   36
} ACPI_DSDT;


typedef struct {
  UINT32 Signature;           //    0
  UINT32 Length;              //    4
  UINT8 Revision;             //    8
  UINT8 Checksum;             //    9
  UINT8 OemId[6];             //   10
  UINT8 OemTableId[8];        //   16
  UINT32 OemRevision;         //   24
  UINT32 CreatorId;           //   28
  UINT32 CreatorRevision;     //   32
  UINT32 FirmwareCtrl;        //   36
  UINT32 DSDT;                //   40
  UINT8 Reserved;             //   44
  UINT8 PreferredPmProfile;   //   45
  UINT16 SciInt;              //   46
  UINT32 SmiCmd;              //   48
  UINT8 AcpiEnable;           //   52
  UINT8 AcpiDisable;          //   53
  UINT8 S4BiosReq;            //   54
  UINT8 PStateCnt;            //   55
  UINT32 Pm1aEvtBlk;          //   56
  UINT32 Pm1bEvtBlk;          //   60
  UINT32 Pm1aCntBlk;          //   64
  UINT32 Pm1bCntBlk;          //   68
  UINT32 Pm2CntBlk;           //   72
  UINT32 PmTmrBlk;            //   76
  UINT32 Gpe0Blk;             //   80
  UINT32 Gpe1Blk;             //   84
  UINT8 Pm1EvtLen;            //   88
  UINT8 Pm1CntLen;            //   89
  UINT8 PM2CntLen;            //   90
  UINT8 PmTmrLen;             //   91
  UINT8 Gpe0BlkLen;           //   92
  UINT8 Gpe1BlkLen;           //   93
  UINT8 Gpe1Base;             //   94
  UINT8 CstCnt;               //   95
  UINT16 PLvl2Lat;            //   96
  UINT16 PLvl3Lat;            //   98
  UINT16 FlushSize;           //  100
  UINT16 FlushStride;         //  102
  UINT8 DutyOffset;           //  104
  UINT8 DutyWidth;            //  105
  UINT8 DayAlrm;              //  106
  UINT8 MonAlrm;              //  107
  UINT8 Century;              //  108
  UINT16 IapcBootArch;        //  109
  UINT8 Reserved2;            //  111
  UINT32 Flags;               //  112
  UINT32 ResetReg[3];         //  116
  UINT8 ResetValue;           //  128
  UINT8 Reserved3[3];         //  129
  UINT64 XFirmwareCtrl;       //  132
  UINT64 XDsdt;               //  140
  UINT32 XPm1aEvtBlk[3];      //  148
  UINT32 XPm1bEvtBlk[3];      //  160
  UINT32 XPm1aCntBlk[3];      //  172
  UINT32 XPm1bCntBlk[3];      //  184
  UINT32 XPm2CntBlk[3];       //  196
  UINT32 XPmTmrBlk[3];        //  208
  UINT32 XGpe0Blk[3];         //  220
  UINT32 XGpe1Blk[3];         //  232
} ACPI_FADT;


typedef struct {
  UINT32 Signature;
  UINT32 Length;
  UINT8 Revision;
  UINT8 Checksum;
  UINT8 OemId[6];
  UINT8 OemTableId[8];
  UINT32 OemRevision;
  UINT32 CreatorId;
  UINT32 CreatorRevision;
  UINT32 Entry[1];
} ACPI_RSDT;


typedef struct {
  UINT32 Signature;           //    0
  UINT32 Length;              //    4
} ACPI_UNKNOWN;

#pragma pack()


typedef struct {
  UINT32 Signature;
  CONST CHAR8 * pTableName;
  CONST CHAR16 * pWebPage;
} TABLE_SIGNATURE;


CONST TABLE_SIGNATURE mTableId[] = {
  { APIC_SIGNATURE, "APIC", PAGE_ACPI_APIC },
  { BGRT_SIGNATURE, "BGRT", PAGE_ACPI_BGRT },
  { DSDT_SIGNATURE, "DSDT", PAGE_ACPI_DSDT },
  { FADT_SIGNATURE, "FADT", PAGE_ACPI_FADT },
  { HPET_SIGNATURE, "HPET", PAGE_ACPI_HPET },
  { MCFG_SIGNATURE, "MCFG", PAGE_ACPI_MCFG },
  { SSDT_SIGNATURE, "SSDT", PAGE_ACPI_SSDT },
  { TCPA_SIGNATURE, "TCPA", PAGE_ACPI_TCPA },
  { UEFI_SIGNATURE, "UEFI", PAGE_ACPI_UEFI }
};


/**
  Locate the RSDT table

  @return  Table address or NULL if not found

**/
CONST ACPI_RSDT *
LocateRsdt (
  VOID
  )
{
  CONST EFI_ACPI_1_0_ROOT_SYSTEM_DESCRIPTION_POINTER * pRsdp10b;
  CONST EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER * pRsdp30;
  CONST ACPI_RSDT * pRsdt;
  EFI_STATUS Status;

  //
  //  Use for/break instead of goto
  //
  pRsdt = NULL;
  for ( ; ; ) {
    //
    //  Locate the RSDT
    //
    Status = EfiGetSystemConfigurationTable ( &gEfiAcpiTableGuid, (VOID **)&pRsdp30 );
    if ( !EFI_ERROR ( Status )) {
      pRsdt = (ACPI_RSDT *)(UINTN)pRsdp30->RsdtAddress;
    }
    else {
      Status = EfiGetSystemConfigurationTable (&gEfiAcpi10TableGuid, (VOID **)&pRsdp10b );
      if ( EFI_ERROR ( Status )) {
        break;
      }
      pRsdt = (ACPI_RSDT *)(UINTN)pRsdp10b->RsdtAddress;
    }
    break;
  }

  //
  //  The entry was not found
  //
  return pRsdt;
}


/**
  Locate the specified table

  @param [in] Signature     Table signature

  @return  Table address or NULL if not found

**/
CONST VOID *
LocateTable (
  IN UINT32 Signature
  )
{
  CONST UINT32 * pEnd;
  CONST UINT32 * pEntry;
  CONST EFI_ACPI_1_0_ROOT_SYSTEM_DESCRIPTION_POINTER * pRsdp10b;
  CONST EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER * pRsdp30;
  CONST ACPI_RSDT * pRsdt;
  CONST UINT32 * pSignature;
  EFI_STATUS Status;

  //
  //  Use for/break instead of goto
  //
  for ( ; ; ) {
    //
    //  Locate the RSDT
    //
    Status = EfiGetSystemConfigurationTable ( &gEfiAcpiTableGuid, (VOID **)&pRsdp30 );
    if ( !EFI_ERROR ( Status )) {
      pRsdt = (ACPI_RSDT *)(UINTN)pRsdp30->RsdtAddress;
    }
    else {
      Status = EfiGetSystemConfigurationTable (&gEfiAcpi10TableGuid, (VOID **)&pRsdp10b );
      if ( EFI_ERROR ( Status )) {
        break;
      }
      pRsdt = (ACPI_RSDT *)(UINTN)pRsdp10b->RsdtAddress;
    }

    //
    //  Walk the list of entries
    //
    pEntry = &pRsdt->Entry[ 0 ];
    pEnd = &pEntry[(( pRsdt->Length - sizeof ( *pRsdt )) >> 2 ) + 1 ];
    while ( pEnd > pEntry ) {
      //
      //  The entry is actually a 32-bit physical table address
      //  The first entry in the table is the 32-bit table signature
      //
      pSignature = (UINT32 *)(UINTN)*pEntry;
      if ( *pSignature == Signature ) {
        return (CONST VOID *)(UINTN)*pEntry;
      }

      //
      //  Set the next entry
      //
      pEntry++;
    }
    break;
  }

  //
  //  The entry was not found
  //
  return NULL;
}


/**
  Display a row containing a hex value

  @param [in] SocketFD      The socket's file descriptor to add to the list.
  @param [in] pPort         The WSDT_PORT structure address
  @param [in] pName         Address of a zero terminated name string
  @param [in] Length        Length in bytes
  @param [in] pChar         Address of the first character

  @retval EFI_SUCCESS       The request was successfully processed

**/
EFI_STATUS
RowAnsiArray (
  IN int SocketFD,
  IN WSDT_PORT * pPort,
  IN CONST CHAR8 * pName,
  IN UINTN Length,
  IN CONST CHAR8 * pChar
  )
{
  CONST CHAR8 * pData;
  CONST CHAR8 * pEnd;
  EFI_STATUS Status;

  DBG_ENTER ( );

  //
  //  Use for/break instead of goto
  //
  for ( ; ; ) {
    //
    //  Start the row
    //
    Status = HttpSendAnsiString ( SocketFD,
                                  pPort,
                                  "<tr><td>" );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = HttpSendAnsiString ( SocketFD,
                                  pPort,
                                  pName );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = HttpSendAnsiString ( SocketFD,
                                  pPort,
                                  "</td><td><code>" );
    if ( EFI_ERROR ( Status )) {
      break;
    }

    //
    //  Display the characters
    //
    pData = pChar;
    pEnd = &pChar[ Length ];
    while ( pEnd > pData ) {
      Status = HttpSendCharacter ( SocketFD,
                                   pPort,
                                   *pData++,
                                   " " );
      if ( EFI_ERROR ( Status )) {
        break;
      }
    }
    if ( EFI_ERROR ( Status )) {
      break;
    }

    //
    //  Display the byte values
    //
    Status = HttpSendAnsiString ( SocketFD,
                                  pPort,
                                  "<br/>0x" );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    pData = pChar;
    while ( pEnd > pData ) {
      Status = HttpSendHexBits ( SocketFD,
                                 pPort,
                                 8,
                                 *pData++ );
      if ( EFI_ERROR ( Status )) {
        break;
      }
      if ( pEnd > pData ) {
        Status = HttpSendAnsiString ( SocketFD,
                                      pPort,
                                      " 0x" );
        if ( EFI_ERROR ( Status )) {
          break;
        }
      }
    }

    //
    //  Terminate the row
    //
    Status = HttpSendAnsiString ( SocketFD,
                                  pPort,
                                  "</code></td></tr>\r\n" );
    break;
  }

  //
  //  Return the operation status
  //
  DBG_EXIT_STATUS ( Status );
  return Status;
}


/**
  Format a row with a list of bytes

  @param [in] SocketFD      The socket's file descriptor to add to the list.
  @param [in] pPort         The WSDT_PORT structure address
  @param [in] pName         Zero terminated name string
  @param [in] ByteCount     The number of bytes to display
  @param [in] pData         Address of the byte array

  @retval EFI_SUCCESS       The request was successfully processed

**/
EFI_STATUS
RowBytes (
  IN int SocketFD,
  IN WSDT_PORT * pPort,
  IN CHAR8 * pName,
  IN UINTN ByteCount,
  IN CONST UINT8 * pData
  )
{
  CONST UINT8 * pEnd;
  EFI_STATUS Status;

  //
  //  Use for/break instead of goto
  //
  for ( ; ; ) {
    //
    //  Start the row
    //
    Status = HttpSendAnsiString ( SocketFD,
                                  pPort,
                                  "<tr><td>" );
    if ( EFI_ERROR ( Status )) {
      break;
    }

    //
    //  Display the field name
    //
    Status = HttpSendAnsiString ( SocketFD,
                                  pPort,
                                  pName );
    if ( EFI_ERROR ( Status )) {
      break;
    }

    //
    //  Display the field value
    //
    Status = HttpSendAnsiString ( SocketFD,
                                  pPort,
                                  "</td><td><code>0x" );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    pEnd = &pData[ ByteCount ];
    while ( pEnd > pData ) {
      Status = HttpSendHexBits ( SocketFD,
                                 pPort,
                                 8,
                                 *pData++ );
      if ( EFI_ERROR ( Status )) {
        break;
      }
      if ( pEnd > pData ) {
        Status = HttpSendAnsiString ( SocketFD,
                                      pPort,
                                      " 0x" );
        if ( EFI_ERROR ( Status )) {
          break;
        }
      }
    }
    if ( EFI_ERROR ( Status )) {
      break;
    }

    //
    //  Terminate the row
    //
    Status = HttpSendAnsiString ( SocketFD,
                                  pPort,
                                  "</code></td></tr>\r\n" );
    break;
  }

  //
  //  Return the operation status
  //
  return Status;
}


/**
  Format a row with a list of bytes

  @param [in] SocketFD      The socket's file descriptor to add to the list.
  @param [in] pPort         The WSDT_PORT structure address
  @param [in] pName         Zero terminated name string
  @param [in] ByteCount     The number of bytes to display
  @param [in] pData         Address of the byte array

  @retval EFI_SUCCESS       The request was successfully processed

**/
EFI_STATUS
RowDump (
  IN int SocketFD,
  IN WSDT_PORT * pPort,
  IN CHAR8 * pName,
  IN UINTN ByteCount,
  IN CONST UINT8 * pData
  )
{
  EFI_STATUS Status;

  //
  //  Use for/break instead of goto
  //
  for ( ; ; ) {
    //
    //  Start the row
    //
    Status = HttpSendAnsiString ( SocketFD,
                                  pPort,
                                  "<tr><td>" );
    if ( EFI_ERROR ( Status )) {
      break;
    }

    //
    //  Display the field name
    //
    Status = HttpSendAnsiString ( SocketFD,
                                  pPort,
                                  pName );
    if ( EFI_ERROR ( Status )) {
      break;
    }

    //
    //  Start the field value
    //
    Status = HttpSendAnsiString ( SocketFD,
                                  pPort,
                                  "</td><td>" );
    if ( EFI_ERROR ( Status )) {
      break;
    }

    //
    //  Dump the buffer
    //
    Status = HttpSendDump ( SocketFD,
                            pPort,
                            ByteCount,
                            pData );

    //
    //  Terminate the field value and row
    //
    Status = HttpSendAnsiString ( SocketFD,
                                  pPort,
                                  "</td></tr>\r\n" );
    break;
  }

  //
  //  Return the operation status
  //
  return Status;
}


/**
  Format a row with a general address

  @param [in] SocketFD      The socket's file descriptor to add to the list.
  @param [in] pPort         The WSDT_PORT structure address
  @param [in] pName         Zero terminated name string
  @param [in] pAddr         Address of the general address buffer
  @param [in] pWebPage      Zero terminated web page address

  @retval EFI_SUCCESS       The request was successfully processed

**/
EFI_STATUS
RowGenericAddress (
  IN int SocketFD,
  IN WSDT_PORT * pPort,
  IN CHAR8 * pName,
  IN CONST UINT32 * pAddr,
  IN CONST CHAR16 * pWebPage
  )
{
  CONST GENERIC_ADDRESS * pGenericAddress;
  EFI_STATUS Status;

  //
  //  Use for/break instead of goto
  //
  for ( ; ; ) {
    //
    //  Start the row
    //
    Status = HttpSendAnsiString ( SocketFD,
                                  pPort,
                                  "<tr><td>" );
    if ( EFI_ERROR ( Status )) {
      break;
    }

    //
    //  Display the field name
    //
    Status = HttpSendAnsiString ( SocketFD,
                                  pPort,
                                  pName );
    if ( EFI_ERROR ( Status )) {
      break;
    }

    //
    //  Display the field value
    //
    Status = HttpSendAnsiString ( SocketFD,
                                  pPort,
                                  "</td><td><code>" );
    if ( EFI_ERROR ( Status )) {
      break;
    }

    //
    //  Determine the type of address
    //
    pGenericAddress = (CONST GENERIC_ADDRESS *)pAddr;
    if ( 0 == pGenericAddress->AddressSpaceId ) {
      Status = HttpSendAnsiString ( SocketFD, pPort, "System Memory" );
    }
    else if ( 1 == pGenericAddress->AddressSpaceId ) {
      Status = HttpSendAnsiString ( SocketFD, pPort, "I/O Space" );
    }
    else if ( 2 == pGenericAddress->AddressSpaceId ) {
      Status = HttpSendAnsiString ( SocketFD, pPort, "PCI Configuration Space" );
    }
    else if ( 3 == pGenericAddress->AddressSpaceId ) {
      Status = HttpSendAnsiString ( SocketFD, pPort, "Embedded Controller" );
    }
    else if ( 4 == pGenericAddress->AddressSpaceId ) {
      Status = HttpSendAnsiString ( SocketFD, pPort, "SMBus" );
    }
    else if ( 0x7f == pGenericAddress->AddressSpaceId ) {
      Status = HttpSendAnsiString ( SocketFD, pPort, "Functional Fixed Hardware" );
    }
    else if (( 0xc0 <= pGenericAddress->AddressSpaceId )
      && ( 0xff >= pGenericAddress->AddressSpaceId )) {
      Status = HttpSendAnsiString ( SocketFD, pPort, "OEM Defined" );
    }
    else {
      Status = HttpSendAnsiString ( SocketFD, pPort, "Reserved" );
    }
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = HttpSendAnsiString ( SocketFD,
                                  pPort,
                                  "<br/>Register Bit Width: " );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = HttpSendValue ( SocketFD,
                             pPort,
                             pGenericAddress->RegisterBitWidth );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = HttpSendAnsiString ( SocketFD,
                                  pPort,
                                  "<br/>Register Bit Offset: " );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = HttpSendHexValue ( SocketFD,
                                pPort,
                                pGenericAddress->RegisterBitOffset );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = HttpSendAnsiString ( SocketFD,
                                  pPort,
                                  "<br/>Access Size: " );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = HttpSendValue ( SocketFD,
                             pPort,
                             pGenericAddress->AccessSize );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = HttpSendAnsiString ( SocketFD,
                                  pPort,
                                  "<br/>Address: " );
    if ( EFI_ERROR ( Status )) {
      break;
    }

    //
    //  Add the web-page link if necessary
    //
    if ( NULL != pWebPage ) {
      Status = HttpSendAnsiString ( SocketFD,
                                    pPort,
                                    "<a target=\"_blank\" href=\"" );
      if ( EFI_ERROR ( Status )) {
        break;
      }
      Status = HttpSendUnicodeString ( SocketFD,
                                       pPort,
                                       pWebPage );
      if ( EFI_ERROR ( Status )) {
        break;
      }
      Status = HttpSendAnsiString ( SocketFD,
                                    pPort,
                                    "\">" );
      if ( EFI_ERROR ( Status )) {
        break;
      }
    }

    //
    //  Display the address
    //
    Status = HttpSendAnsiString ( SocketFD,
                                  pPort,
                                  "0x" );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = HttpSendHexBits ( SocketFD,
                               pPort,
                               64,
                               pGenericAddress->Address );
    if ( EFI_ERROR ( Status )) {
      break;
    }

    //
    //  Finish the web-page link if necessary
    //
    if ( NULL != pWebPage ) {
      Status = HttpSendAnsiString ( SocketFD,
                                    pPort,
                                    "</a>" );
      if ( EFI_ERROR ( Status )) {
        break;
      }
    }

    //
    //  Terminate the row
    //
    Status = HttpSendAnsiString ( SocketFD,
                                  pPort,
                                  "</code></td></tr>\r\n" );
    break;
  }

  //
  //  Return the operation status
  //
  return Status;
}


/**
  Translate a table address into a web page

  @param [in] pSignature      Address of the table signature
  @param [out] ppTableName    Address to receive the table name address

  @return  Zero terminated web page address or NULL if not found

**/
CONST CHAR16 *
SignatureLookup (
  IN UINT32 * pSignature,
  OUT CONST CHAR8 ** ppTableName
  )
{
  CONST TABLE_SIGNATURE * pTableId;
  CONST TABLE_SIGNATURE * pEnd;
  UINT32 Signature;

  //
  //  Walk the list of tables
  //
  Signature = *pSignature;
  pTableId = &mTableId[ 0 ];
  pEnd = &pTableId[ sizeof ( mTableId ) / sizeof ( mTableId[ 0 ])];
  while ( pEnd > pTableId ) {
    //
    //  Attempt to locate the table signature
    //
    if ( pTableId->Signature == Signature ) {
      //
      //  The signature was found
      //  Return the web page
      //
      *ppTableName = pTableId->pTableName;
      return pTableId->pWebPage;
    }

    //
    //  Set the next table
    //
    pTableId += 1;
  }

  //
  //  The table was not found
  //
  *ppTableName = (CONST CHAR8 *)pSignature;
  return NULL;
}


/**
  Respond with the APIC table

  @param [in] SocketFD      The socket's file descriptor to add to the list.
  @param [in] pPort         The WSDT_PORT structure address
  @param [out] pbDone       Address to receive the request completion status

  @retval EFI_SUCCESS       The request was successfully processed

**/
EFI_STATUS
AcpiApicPage (
  IN int SocketFD,
  IN WSDT_PORT * pPort,
  OUT BOOLEAN * pbDone
  )
{
  CONST ACPI_UNKNOWN * pApic;
  EFI_STATUS Status;

  DBG_ENTER ( );

  //
  //  Send the APIC page
  //
  for ( ; ; ) {
    //
    //  Locate the APIC
    //
    pApic = (ACPI_UNKNOWN *)LocateTable ( APIC_SIGNATURE );
    if ( NULL == pApic ) {
      Status = EFI_NOT_FOUND;
      break;
    }

    //
    //  Send the page and table header
    //
    Status = TableHeader ( SocketFD, pPort, L"APIC Table", pApic );
    if ( EFI_ERROR ( Status )) {
      break;
    }

    //
    //  Display the header
    //
    Status = RowAnsiArray ( SocketFD,
                            pPort,
                            "Signature",
                            sizeof ( pApic->Signature ),
                            (CHAR8 *)&pApic->Signature );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowDecimalValue ( SocketFD,
                               pPort,
                               "Length",
                               pApic->Length );
    if ( EFI_ERROR ( Status )) {
      break;
    }

    //
    //  Display the data from the table
    //
    Status = RowDump ( SocketFD,
                       pPort,
                       "Data",
                       pApic->Length - sizeof ( *pApic ) + 1,
                       (UINT8 *)( pApic + 1 ));
    if ( EFI_ERROR ( Status )) {
      break;
    }

    //
    //  Build the table trailer
    //
    Status = TableTrailer ( SocketFD,
                            pPort,
                            pbDone );
    break;
  }

  //
  //  Return the operation status
  //
  DBG_EXIT_STATUS ( Status );
  return Status;
}


/**
  Respond with the BGRT table

  @param [in] SocketFD      The socket's file descriptor to add to the list.
  @param [in] pPort         The WSDT_PORT structure address
  @param [out] pbDone       Address to receive the request completion status

  @retval EFI_SUCCESS       The request was successfully processed

**/
EFI_STATUS
AcpiBgrtPage (
  IN int SocketFD,
  IN WSDT_PORT * pPort,
  OUT BOOLEAN * pbDone
  )
{
  CONST ACPI_UNKNOWN * pBgrt;
  EFI_STATUS Status;

  DBG_ENTER ( );

  //
  //  Send the BGRT page
  //
  for ( ; ; ) {
    //
    //  Locate the BGRT
    //
    pBgrt = (ACPI_UNKNOWN *)LocateTable ( BGRT_SIGNATURE );
    if ( NULL == pBgrt ) {
      Status = EFI_NOT_FOUND;
      break;
    }

    //
    //  Send the page and table header
    //
    Status = TableHeader ( SocketFD, pPort, L"BGRT Table", pBgrt );
    if ( EFI_ERROR ( Status )) {
      break;
    }

    //
    //  Display the header
    //
    Status = RowAnsiArray ( SocketFD,
                            pPort,
                            "Signature",
                            sizeof ( pBgrt->Signature ),
                            (CHAR8 *)&pBgrt->Signature );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowDecimalValue ( SocketFD,
                               pPort,
                               "Length",
                               pBgrt->Length );
    if ( EFI_ERROR ( Status )) {
      break;
    }

    //
    //  Display the data from the table
    //
    Status = RowDump ( SocketFD,
                       pPort,
                       "Data",
                       pBgrt->Length - sizeof ( *pBgrt ) + 1,
                       (UINT8 *)( pBgrt + 1 ));
    if ( EFI_ERROR ( Status )) {
      break;
    }

    //
    //  Build the table trailer
    //
    Status = TableTrailer ( SocketFD,
                            pPort,
                            pbDone );
    break;
  }

  //
  //  Return the operation status
  //
  DBG_EXIT_STATUS ( Status );
  return Status;
}


/**
  Respond with the ACPI DSDT table

  @param [in] SocketFD      The socket's file descriptor to add to the list.
  @param [in] pPort         The WSDT_PORT structure address
  @param [out] pbDone       Address to receive the request completion status

  @retval EFI_SUCCESS       The request was successfully processed

**/
EFI_STATUS
AcpiDsdtPage (
  IN int SocketFD,
  IN WSDT_PORT * pPort,
  OUT BOOLEAN * pbDone
  )
{
  CONST ACPI_DSDT * pDsdt;
  CONST ACPI_FADT * pFadt;
  EFI_STATUS Status;

  DBG_ENTER ( );

  //
  //  Send the DADT page
  //
  for ( ; ; ) {
    //
    //  Locate the DADT
    //
    pFadt = (ACPI_FADT *)LocateTable ( FADT_SIGNATURE );
    if ( NULL == pFadt ) {
      Status = EFI_NOT_FOUND;
      break;
    }
    pDsdt = (VOID *)(UINTN)pFadt->XDsdt;

    //
    //  Send the page and table header
    //
    Status = TableHeader ( SocketFD, pPort, L"DSDT - Differentiated System Description Table", pDsdt );
    if ( EFI_ERROR ( Status )) {
      break;
    }

    //
    //  Display the DSDT header
    //
    Status = RowAnsiArray ( SocketFD,
                            pPort,
                            "Signature",
                            sizeof ( pDsdt->Signature ),
                            (CHAR8 *)&pDsdt->Signature );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowDecimalValue ( SocketFD,
                               pPort,
                               "Length",
                               pDsdt->Length );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowDecimalValue ( SocketFD,
                               pPort,
                               "Revision",
                               pDsdt->Revision );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowHexValue ( SocketFD,
                           pPort,
                           "Checksum",
                           pDsdt->Checksum,
                           NULL );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowAnsiArray ( SocketFD,
                            pPort,
                            "OEMID",
                            sizeof ( pDsdt->OemId ),
                            (CONST CHAR8 *)&pDsdt->OemId[ 0 ]);
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowAnsiArray ( SocketFD,
                            pPort,
                            "OEM Table ID",
                            sizeof ( pDsdt->OemTableId ),
                            (CONST CHAR8 *)&pDsdt->OemTableId[ 0 ]);
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowRevision ( SocketFD,
                           pPort,
                           "OEM Revision",
                           pDsdt->OemRevision );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowAnsiArray ( SocketFD,
                            pPort,
                            "Creator ID",
                            sizeof ( pDsdt->CreatorId ),
                            (CHAR8 *)&pDsdt->CreatorId );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowRevision ( SocketFD,
                           pPort,
                           "Creator Revision",
                           pDsdt->CreatorRevision );
    if ( EFI_ERROR ( Status )) {
      break;
    }

    //
    //  Display the data from the DSDT
    //
    Status = RowDump ( SocketFD,
                       pPort,
                       "Definition Block",
                       pDsdt->Length - sizeof ( *pDsdt ) + 1,
                       &pDsdt->DefinitionBlock[0]);
    if ( EFI_ERROR ( Status )) {
      break;
    }

    //
    //  Build the table trailer
    //
    Status = TableTrailer ( SocketFD,
                            pPort,
                            pbDone );
    break;
  }

  //
  //  Return the operation status
  //
  DBG_EXIT_STATUS ( Status );
  return Status;
}


/**
  Respond with the ACPI FADT table

  @param [in] SocketFD      The socket's file descriptor to add to the list.
  @param [in] pPort         The WSDT_PORT structure address
  @param [out] pbDone       Address to receive the request completion status

  @retval EFI_SUCCESS       The request was successfully processed

**/
EFI_STATUS
AcpiFadtPage (
  IN int SocketFD,
  IN WSDT_PORT * pPort,
  OUT BOOLEAN * pbDone
  )
{
  CONST ACPI_FADT * pFadt;
  EFI_STATUS Status;

  DBG_ENTER ( );

  //
  //  Send the FADT page
  //
  for ( ; ; ) {
    //
    //  Locate the FADT
    //
    pFadt = (ACPI_FADT *)LocateTable ( FADT_SIGNATURE );
    if ( NULL == pFadt ) {
      Status = EFI_NOT_FOUND;
      break;
    }

    //
    //  Send the page and table header
    //
    Status = TableHeader ( SocketFD, pPort, L"FADT - Fixed ACPI Description Table", pFadt );
    if ( EFI_ERROR ( Status )) {
      break;
    }

    //
    //  Display the FSDT header
    //
    Status = RowAnsiArray ( SocketFD,
                            pPort,
                            "Signature",
                            sizeof ( pFadt->Signature ),
                            (CHAR8 *)&pFadt->Signature );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowDecimalValue ( SocketFD,
                               pPort,
                               "Length",
                               pFadt->Length );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowDecimalValue ( SocketFD,
                               pPort,
                               "Revision",
                               pFadt->Revision );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowHexValue ( SocketFD,
                           pPort,
                           "Checksum",
                           pFadt->Checksum,
                           NULL );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowAnsiArray ( SocketFD,
                            pPort,
                            "OEMID",
                            sizeof ( pFadt->OemId ),
                            (CONST CHAR8 *)&pFadt->OemId[ 0 ]);
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowAnsiArray ( SocketFD,
                            pPort,
                            "OEM Table ID",
                            sizeof ( pFadt->OemTableId ),
                            (CONST CHAR8 *)&pFadt->OemTableId[ 0 ]);
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowRevision ( SocketFD,
                           pPort,
                           "OEM Revision",
                           pFadt->OemRevision );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowAnsiArray ( SocketFD,
                            pPort,
                            "Creator ID",
                            sizeof ( pFadt->CreatorId ),
                            (CHAR8 *)&pFadt->CreatorId );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowRevision ( SocketFD,
                           pPort,
                           "Creator Revision",
                           pFadt->CreatorRevision );
    if ( EFI_ERROR ( Status )) {
      break;
    }

    //
    //  Display the data from the FADT
    //
    Status = RowPointer ( SocketFD,
                          pPort,
                          "FIRMWARE_CTRL",
                          (CONST VOID *)(UINTN)pFadt->FirmwareCtrl,
                          NULL );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowPointer ( SocketFD,
                          pPort,
                          "DSDT",
                          (CONST VOID *)(UINTN)pFadt->DSDT,
                          ( pFadt->DSDT == pFadt->XDsdt ) ? PAGE_ACPI_DSDT : NULL );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowHexValue ( SocketFD,
                           pPort,
                           "Reserved",
                           pFadt->Reserved,
                           NULL );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowHexValue ( SocketFD,
                           pPort,
                           "Preferred_PM_Profile",
                           pFadt->PreferredPmProfile,
                           NULL );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowHexValue ( SocketFD,
                           pPort,
                           "SCI_INT",
                           pFadt->SciInt,
                           NULL );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowHexValue ( SocketFD,
                           pPort,
                           "SMI_CMD",
                           pFadt->SmiCmd,
                           NULL );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowHexValue ( SocketFD,
                           pPort,
                           "ACPI_ENABLE",
                           pFadt->AcpiEnable,
                           NULL );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowHexValue ( SocketFD,
                           pPort,
                           "ACPI_DISABLE",
                           pFadt->AcpiDisable,
                           NULL );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowHexValue ( SocketFD,
                           pPort,
                           "S4BIOS_REQ",
                           pFadt->S4BiosReq,
                           NULL );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowHexValue ( SocketFD,
                           pPort,
                           "PSTATE_CNT",
                           pFadt->PStateCnt,
                           NULL );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowHexValue ( SocketFD,
                           pPort,
                           "PM1a_EVT_BLK",
                           pFadt->Pm1aEvtBlk,
                           NULL );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowHexValue ( SocketFD,
                           pPort,
                           "PM1b_EVT_BLK",
                           pFadt->Pm1bEvtBlk,
                           NULL );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowHexValue ( SocketFD,
                           pPort,
                           "PM1a_CNT_BLK",
                           pFadt->Pm1aCntBlk,
                           NULL );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowHexValue ( SocketFD,
                           pPort,
                           "PM1b_CNT_BLK",
                           pFadt->Pm1bCntBlk,
                           NULL );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowHexValue ( SocketFD,
                           pPort,
                           "PM2_CNT_BLK",
                           pFadt->Pm2CntBlk,
                           NULL );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowHexValue ( SocketFD,
                           pPort,
                           "PM_TMR_BLK",
                           pFadt->PmTmrBlk,
                           NULL );
    if ( EFI_ERROR ( Status )) {
      break;
    }

    Status = RowHexValue ( SocketFD,
                           pPort,
                           "GPE0_BLK",
                           pFadt->Gpe0Blk,
                           NULL );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowHexValue ( SocketFD,
                           pPort,
                           "GPE1_BLK",
                           pFadt->Gpe1Blk,
                           NULL );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowDecimalValue ( SocketFD,
                               pPort,
                               "PM1_EVT_LEN",
                               pFadt->Pm1EvtLen );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowDecimalValue ( SocketFD,
                               pPort,
                               "PM1_CNT_LEN",
                               pFadt->Pm1CntLen );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowDecimalValue ( SocketFD,
                               pPort,
                               "PM2_CNT_LEN",
                               pFadt->PM2CntLen );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowDecimalValue ( SocketFD,
                               pPort,
                               "PM_TMR_LEN",
                               pFadt->PmTmrLen );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowDecimalValue ( SocketFD,
                               pPort,
                               "GPE0_BLK_LEN",
                               pFadt->Gpe0BlkLen );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowDecimalValue ( SocketFD,
                               pPort,
                               "GPE1_BLK_LEN",
                               pFadt->Gpe1BlkLen );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowHexValue ( SocketFD,
                           pPort,
                           "GPE1_BASE",
                           pFadt->Gpe1Base,
                           NULL );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowDecimalValue ( SocketFD,
                               pPort,
                               "CST_CNT",
                               pFadt->CstCnt );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowHexValue ( SocketFD,
                           pPort,
                           "P_LVL2_LAT",
                           pFadt->PLvl2Lat,
                           NULL );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowHexValue ( SocketFD,
                           pPort,
                           "P_LVL3_LAT",
                           pFadt->PLvl3Lat,
                           NULL );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowDecimalValue ( SocketFD,
                               pPort,
                               "FLUSH_SIZE",
                               pFadt->FlushSize );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowDecimalValue ( SocketFD,
                               pPort,
                               "FLUSH_Stride",
                               pFadt->FlushStride );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowHexValue ( SocketFD,
                           pPort,
                           "DUTY_OFFSET",
                           pFadt->DutyOffset,
                           NULL );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowHexValue ( SocketFD,
                           pPort,
                           "DUTY_WIDTH",
                           pFadt->DutyWidth,
                           NULL );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowHexValue ( SocketFD,
                           pPort,
                           "DAY_ALRM",
                           pFadt->DayAlrm,
                           NULL );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowHexValue ( SocketFD,
                           pPort,
                           "MON_ALRM",
                           pFadt->MonAlrm,
                           NULL );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowHexValue ( SocketFD,
                           pPort,
                           "CENTURY",
                           pFadt->Century,
                           NULL );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowHexValue ( SocketFD,
                           pPort,
                           "IAPC_BOOT_ARCH",
                           pFadt->IapcBootArch,
                           NULL );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowHexValue ( SocketFD,
                           pPort,
                           "Reserved",
                           pFadt->Reserved2,
                           NULL );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowHexValue ( SocketFD,
                           pPort,
                           "Flags",
                           pFadt->Flags,
                           NULL );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowGenericAddress ( SocketFD,
                                 pPort,
                                 "RESET_REG",
                                 &pFadt->ResetReg[0],
                                 NULL );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowHexValue ( SocketFD,
                           pPort,
                           "RESET_VALUE",
                           pFadt->ResetValue,
                           NULL );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowHexValue ( SocketFD,
                           pPort,
                           "Reserved",
                           pFadt->Reserved3[0],
                           NULL );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowHexValue ( SocketFD,
                           pPort,
                           "Reserved",
                           pFadt->Reserved3[1],
                           NULL );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowHexValue ( SocketFD,
                           pPort,
                           "Reserved",
                           pFadt->Reserved3[2],
                           NULL );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowHexValue ( SocketFD,
                           pPort,
                           "X_FIRMWARE_CTRL",
                           pFadt->XFirmwareCtrl,
                           NULL );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowHexValue ( SocketFD,
                           pPort,
                           "X_DSDT",
                           pFadt->XDsdt,
                           PAGE_ACPI_DSDT );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowGenericAddress ( SocketFD,
                                 pPort,
                                 "X_PM1a_EVT_BLK",
                                 &pFadt->XPm1aEvtBlk[0],
                                 NULL );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowGenericAddress ( SocketFD,
                                 pPort,
                                 "X_PM1b_EVT_BLK",
                                 &pFadt->XPm1bEvtBlk[0],
                                 NULL );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowGenericAddress ( SocketFD,
                                 pPort,
                                 "X_PM1a_CNT_BLK",
                                 &pFadt->XPm1aCntBlk[0],
                                 NULL );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowGenericAddress ( SocketFD,
                                 pPort,
                                 "X_PM1b_CNT_BLK",
                                 &pFadt->XPm1bCntBlk[0],
                                 NULL );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowGenericAddress ( SocketFD,
                                 pPort,
                                 "X_PM2_CNT_BLK",
                                 &pFadt->XPm2CntBlk[0],
                                 NULL );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowGenericAddress ( SocketFD,
                                 pPort,
                                 "X_PM_TMR_BLK",
                                 &pFadt->XPmTmrBlk[0],
                                 NULL );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowGenericAddress ( SocketFD,
                                 pPort,
                                 "X_GPE0_BLK",
                                 &pFadt->XGpe0Blk[0],
                                 NULL );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowGenericAddress ( SocketFD,
                                 pPort,
                                 "X_GPE1_BLK",
                                 &pFadt->XGpe1Blk[0],
                                 NULL );
    if ( EFI_ERROR ( Status )) {
      break;
    }

    //
    //  Build the table trailer
    //
    Status = TableTrailer ( SocketFD,
                            pPort,
                            pbDone );
    break;
  }

  //
  //  Return the operation status
  //
  DBG_EXIT_STATUS ( Status );
  return Status;
}


/**
  Respond with the HPET table

  @param [in] SocketFD      The socket's file descriptor to add to the list.
  @param [in] pPort         The WSDT_PORT structure address
  @param [out] pbDone       Address to receive the request completion status

  @retval EFI_SUCCESS       The request was successfully processed

**/
EFI_STATUS
AcpiHpetPage (
  IN int SocketFD,
  IN WSDT_PORT * pPort,
  OUT BOOLEAN * pbDone
  )
{
  CONST ACPI_UNKNOWN * pHpet;
  EFI_STATUS Status;

  DBG_ENTER ( );

  //
  //  Send the HPET page
  //
  for ( ; ; ) {
    //
    //  Locate the HPET
    //
    pHpet = (ACPI_UNKNOWN *)LocateTable ( HPET_SIGNATURE );
    if ( NULL == pHpet ) {
      Status = EFI_NOT_FOUND;
      break;
    }

    //
    //  Send the page and table header
    //
    Status = TableHeader ( SocketFD, pPort, L"HPET Table", pHpet );
    if ( EFI_ERROR ( Status )) {
      break;
    }

    //
    //  Display the header
    //
    Status = RowAnsiArray ( SocketFD,
                            pPort,
                            "Signature",
                            sizeof ( pHpet->Signature ),
                            (CHAR8 *)&pHpet->Signature );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowDecimalValue ( SocketFD,
                               pPort,
                               "Length",
                               pHpet->Length );
    if ( EFI_ERROR ( Status )) {
      break;
    }

    //
    //  Display the data from the table
    //
    Status = RowDump ( SocketFD,
                       pPort,
                       "Data",
                       pHpet->Length - sizeof ( *pHpet ) + 1,
                       (UINT8 *)( pHpet + 1 ));
    if ( EFI_ERROR ( Status )) {
      break;
    }

    //
    //  Build the table trailer
    //
    Status = TableTrailer ( SocketFD,
                            pPort,
                            pbDone );
    break;
  }

  //
  //  Return the operation status
  //
  DBG_EXIT_STATUS ( Status );
  return Status;
}


/**
  Respond with the MCFG table

  @param [in] SocketFD      The socket's file descriptor to add to the list.
  @param [in] pPort         The WSDT_PORT structure address
  @param [out] pbDone       Address to receive the request completion status

  @retval EFI_SUCCESS       The request was successfully processed

**/
EFI_STATUS
AcpiMcfgPage (
  IN int SocketFD,
  IN WSDT_PORT * pPort,
  OUT BOOLEAN * pbDone
  )
{
  CONST ACPI_UNKNOWN * pMcfg;
  EFI_STATUS Status;

  DBG_ENTER ( );

  //
  //  Send the MCFG page
  //
  for ( ; ; ) {
    //
    //  Locate the MCFG
    //
    pMcfg = (ACPI_UNKNOWN *)LocateTable ( MCFG_SIGNATURE );
    if ( NULL == pMcfg ) {
      Status = EFI_NOT_FOUND;
      break;
    }

    //
    //  Send the page and table header
    //
    Status = TableHeader ( SocketFD, pPort, L"MCFG Table", pMcfg );
    if ( EFI_ERROR ( Status )) {
      break;
    }

    //
    //  Display the header
    //
    Status = RowAnsiArray ( SocketFD,
                            pPort,
                            "Signature",
                            sizeof ( pMcfg->Signature ),
                            (CHAR8 *)&pMcfg->Signature );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowDecimalValue ( SocketFD,
                               pPort,
                               "Length",
                               pMcfg->Length );
    if ( EFI_ERROR ( Status )) {
      break;
    }

    //
    //  Display the data from the table
    //
    Status = RowDump ( SocketFD,
                       pPort,
                       "Data",
                       pMcfg->Length - sizeof ( *pMcfg ) + 1,
                       (UINT8 *)( pMcfg + 1 ));
    if ( EFI_ERROR ( Status )) {
      break;
    }

    //
    //  Build the table trailer
    //
    Status = TableTrailer ( SocketFD,
                            pPort,
                            pbDone );
    break;
  }

  //
  //  Return the operation status
  //
  DBG_EXIT_STATUS ( Status );
  return Status;
}


/**
  Respond with the ACPI RSDP 1.0b table

  @param [in] SocketFD      The socket's file descriptor to add to the list.
  @param [in] pPort         The WSDT_PORT structure address
  @param [out] pbDone       Address to receive the request completion status

  @retval EFI_SUCCESS       The request was successfully processed

**/
EFI_STATUS
AcpiRsdp10Page (
  IN int SocketFD,
  IN WSDT_PORT * pPort,
  OUT BOOLEAN * pbDone
  )
{
  CONST EFI_ACPI_1_0_ROOT_SYSTEM_DESCRIPTION_POINTER * pRsdp10b;
  EFI_STATUS Status;

  DBG_ENTER ( );

  //
  //  Send the RSDP page
  //
  for ( ; ; ) {
    //
    //  Locate the RSDP
    //
    Status = EfiGetSystemConfigurationTable ( &gEfiAcpi10TableGuid, (VOID **) &pRsdp10b );
    if ( EFI_ERROR ( Status )) {
      break;
    }

    //
    //  Send the page and table header
    //
    Status = TableHeader ( SocketFD, pPort, L"RSDP - ACPI 1.0b Root System Description Pointer", pRsdp10b );
    if ( EFI_ERROR ( Status )) {
      break;
    }

    //
    //  Display the RSDP
    //
    Status = RowAnsiArray ( SocketFD,
                            pPort,
                            "Signature",
                            sizeof ( pRsdp10b->Signature ),
                            (CHAR8 *)&pRsdp10b->Signature );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowHexValue ( SocketFD,
                           pPort,
                           "Checksum",
                           pRsdp10b->Checksum,
                           NULL );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowAnsiArray ( SocketFD,
                            pPort,
                            "OemId",
                            sizeof ( pRsdp10b->OemId ),
                            (CONST CHAR8 *)&pRsdp10b->OemId[ 0 ]);
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowHexValue ( SocketFD,
                           pPort,
                           "Reserved",
                           pRsdp10b->Reserved,
                           NULL );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowPointer ( SocketFD,
                          pPort,
                          "RsdtAddress",
                          (VOID *)(UINTN)pRsdp10b->RsdtAddress,
                          PAGE_ACPI_RSDT );
    if ( EFI_ERROR ( Status )) {
      break;
    }

    //
    //  Build the table trailer
    //
    Status = TableTrailer ( SocketFD,
                            pPort,
                            pbDone );
    break;
  }

  //
  //  Return the operation status
  //
  DBG_EXIT_STATUS ( Status );
  return Status;
}


/**
  Respond with the ACPI RSDP 3.0 table

  @param [in] SocketFD      The socket's file descriptor to add to the list.
  @param [in] pPort         The WSDT_PORT structure address
  @param [out] pbDone       Address to receive the request completion status

  @retval EFI_SUCCESS       The request was successfully processed

**/
EFI_STATUS
AcpiRsdp30Page (
  IN int SocketFD,
  IN WSDT_PORT * pPort,
  OUT BOOLEAN * pbDone
  )
{
  CONST EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER * pRsdp30;
  EFI_STATUS Status;

  DBG_ENTER ( );

  //
  //  Send the RSDP page
  //
  for ( ; ; ) {
    //
    //  Locate the RSDP
    //
    Status = EfiGetSystemConfigurationTable ( &gEfiAcpiTableGuid, (VOID **) &pRsdp30 );
    if ( EFI_ERROR ( Status )) {
      break;
    }

    //
    //  Send the page and table header
    //
    Status = TableHeader ( SocketFD, pPort, L"RSDP - ACPI 3.0 Root System Description Pointer", pRsdp30 );
    if ( EFI_ERROR ( Status )) {
      break;
    }

    //
    //  Display the RSDP
    //
    Status = RowAnsiArray ( SocketFD,
                            pPort,
                            "Signature",
                            sizeof ( pRsdp30->Signature ),
                            (CHAR8 *)&pRsdp30->Signature );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowHexValue ( SocketFD,
                           pPort,
                           "Checksum",
                           pRsdp30->Checksum,
                           NULL );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowAnsiArray ( SocketFD,
                            pPort,
                            "OemId",
                            sizeof ( pRsdp30->OemId ),
                            (CONST CHAR8 *)&pRsdp30->OemId[ 0 ]);
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowHexValue ( SocketFD,
                           pPort,
                           "Revision",
                           pRsdp30->Revision,
                           NULL );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowPointer ( SocketFD,
                          pPort,
                          "RsdtAddress",
                          (VOID *)(UINTN)pRsdp30->RsdtAddress,
                          PAGE_ACPI_RSDT );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowDecimalValue ( SocketFD,
                               pPort,
                               "Length",
                               pRsdp30->Length );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowPointer ( SocketFD,
                          pPort,
                          "XsdtAddress",
                          (VOID *)(UINTN)pRsdp30->XsdtAddress,
                          NULL );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowHexValue ( SocketFD,
                           pPort,
                           "ExtendedChecksum",
                           pRsdp30->ExtendedChecksum,
                           NULL );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowBytes ( SocketFD,
                        pPort,
                        "Reserved",
                        sizeof ( pRsdp30->Reserved ),
                        &pRsdp30->Reserved[ 0 ]);
    if ( EFI_ERROR ( Status )) {
      break;
    }

    //
    //  Build the table trailer
    //
    Status = TableTrailer ( SocketFD,
                            pPort,
                            pbDone );
    break;
  }

  //
  //  Return the operation status
  //
  DBG_EXIT_STATUS ( Status );
  return Status;
}


/**
  Respond with the ACPI RSDT table

  @param [in] SocketFD      The socket's file descriptor to add to the list.
  @param [in] pPort         The WSDT_PORT structure address
  @param [out] pbDone       Address to receive the request completion status

  @retval EFI_SUCCESS       The request was successfully processed

**/
EFI_STATUS
AcpiRsdtPage (
  IN int SocketFD,
  IN WSDT_PORT * pPort,
  OUT BOOLEAN * pbDone
  )
{
  CONST UINT32 * pEnd;
  CONST UINT32 * pEntry;
  CONST ACPI_RSDT * pRsdt;
  CONST CHAR8 * pTableName;
  CONST CHAR16 * pWebPage;
  EFI_STATUS Status;
  UINT32 TableName[ 2 ];

  DBG_ENTER ( );

  //
  //  Send the RSDT page
  //
  for ( ; ; ) {
    //
    //  Locate the RSDT
    //
    pRsdt = LocateRsdt ( );
    if ( NULL == pRsdt ) {
      Status = EFI_NOT_FOUND;
      break;
    }

    //
    //  Send the page and table header
    //
    Status = TableHeader ( SocketFD, pPort, L"RSDT - ACPI Root System Description Table", pRsdt );
    if ( EFI_ERROR ( Status )) {
      break;
    }

    //
    //  Display the RSDT
    //
    Status = RowAnsiArray ( SocketFD,
                            pPort,
                            "Signature",
                            sizeof ( pRsdt->Signature ),
                            (CHAR8 *)&pRsdt->Signature );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowDecimalValue ( SocketFD,
                               pPort,
                               "Length",
                               pRsdt->Length );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowDecimalValue ( SocketFD,
                               pPort,
                               "Revision",
                               pRsdt->Revision );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowHexValue ( SocketFD,
                           pPort,
                           "Checksum",
                           pRsdt->Checksum,
                           NULL );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowAnsiArray ( SocketFD,
                            pPort,
                            "OEMID",
                            sizeof ( pRsdt->OemId ),
                            (CONST CHAR8 *)&pRsdt->OemId[ 0 ]);
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowAnsiArray ( SocketFD,
                            pPort,
                            "OEM Table ID",
                            sizeof ( pRsdt->OemTableId ),
                            (CONST CHAR8 *)&pRsdt->OemTableId[ 0 ]);
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowRevision ( SocketFD,
                           pPort,
                           "OEM Revision",
                           pRsdt->OemRevision );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowAnsiArray ( SocketFD,
                            pPort,
                            "Creator ID",
                            sizeof ( pRsdt->CreatorId ),
                            (CHAR8 *)&pRsdt->CreatorId );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowRevision ( SocketFD,
                           pPort,
                           "Creator Revision",
                           pRsdt->CreatorRevision );
    if ( EFI_ERROR ( Status )) {
      break;
    }

    //
    //  Walk the list of entries
    //
    pEntry = &pRsdt->Entry[ 0 ];
    pEnd = &pEntry[(( pRsdt->Length - sizeof ( *pRsdt )) >> 2 ) + 1 ];
    TableName[ 1 ] = 0;
    while ( pEnd > pEntry ) {
      //
      //  The entry is actually a 32-bit physical table address
      //  The first entry in the table is the 32-bit table signature
      //
      TableName[ 0 ] = *(UINT32 *)(UINTN)*pEntry;
      pWebPage = SignatureLookup ( &TableName[ 0 ], &pTableName );

      //
      //  Display the table address
      //
      Status = RowPointer ( SocketFD,
                            pPort,
                            pTableName,
                            (VOID *)(UINTN)*pEntry,
                            pWebPage );
      if ( EFI_ERROR ( Status )) {
        break;
      }
      pEntry++;
    }
    if ( EFI_ERROR ( Status )) {
      break;
    }

    //
    //  Build the table trailer
    //
    Status = TableTrailer ( SocketFD,
                            pPort,
                            pbDone );
    break;
  }

  //
  //  Return the operation status
  //
  DBG_EXIT_STATUS ( Status );
  return Status;
}


/**
  Respond with the SSDT table

  @param [in] SocketFD      The socket's file descriptor to add to the list.
  @param [in] pPort         The WSDT_PORT structure address
  @param [out] pbDone       Address to receive the request completion status

  @retval EFI_SUCCESS       The request was successfully processed

**/
EFI_STATUS
AcpiSsdtPage (
  IN int SocketFD,
  IN WSDT_PORT * pPort,
  OUT BOOLEAN * pbDone
  )
{
  CONST ACPI_UNKNOWN * pSsdt;
  EFI_STATUS Status;

  DBG_ENTER ( );

  //
  //  Send the SSDT page
  //
  for ( ; ; ) {
    //
    //  Locate the SSDT
    //
    pSsdt = (ACPI_UNKNOWN *)LocateTable ( SSDT_SIGNATURE );
    if ( NULL == pSsdt ) {
      Status = EFI_NOT_FOUND;
      break;
    }

    //
    //  Send the page and table header
    //
    Status = TableHeader ( SocketFD, pPort, L"SSDT Table", pSsdt );
    if ( EFI_ERROR ( Status )) {
      break;
    }

    //
    //  Display the header
    //
    Status = RowAnsiArray ( SocketFD,
                            pPort,
                            "Signature",
                            sizeof ( pSsdt->Signature ),
                            (CHAR8 *)&pSsdt->Signature );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowDecimalValue ( SocketFD,
                               pPort,
                               "Length",
                               pSsdt->Length );
    if ( EFI_ERROR ( Status )) {
      break;
    }

    //
    //  Display the data from the table
    //
    Status = RowDump ( SocketFD,
                       pPort,
                       "Data",
                       pSsdt->Length - sizeof ( *pSsdt ) + 1,
                       (UINT8 *)( pSsdt + 1 ));
    if ( EFI_ERROR ( Status )) {
      break;
    }

    //
    //  Build the table trailer
    //
    Status = TableTrailer ( SocketFD,
                            pPort,
                            pbDone );
    break;
  }

  //
  //  Return the operation status
  //
  DBG_EXIT_STATUS ( Status );
  return Status;
}


/**
  Respond with the TCPA table

  @param [in] SocketFD      The socket's file descriptor to add to the list.
  @param [in] pPort         The WSDT_PORT structure address
  @param [out] pbDone       Address to receive the request completion status

  @retval EFI_SUCCESS       The request was successfully processed

**/
EFI_STATUS
AcpiTcpaPage (
  IN int SocketFD,
  IN WSDT_PORT * pPort,
  OUT BOOLEAN * pbDone
  )
{
  CONST ACPI_UNKNOWN * pTcpa;
  EFI_STATUS Status;

  DBG_ENTER ( );

  //
  //  Send the TCPA page
  //
  for ( ; ; ) {
    //
    //  Locate the TCPA
    //
    pTcpa = (ACPI_UNKNOWN *)LocateTable ( TCPA_SIGNATURE );
    if ( NULL == pTcpa ) {
      Status = EFI_NOT_FOUND;
      break;
    }

    //
    //  Send the page and table header
    //
    Status = TableHeader ( SocketFD, pPort, L"TCPA Table", pTcpa );
    if ( EFI_ERROR ( Status )) {
      break;
    }

    //
    //  Display the header
    //
    Status = RowAnsiArray ( SocketFD,
                            pPort,
                            "Signature",
                            sizeof ( pTcpa->Signature ),
                            (CHAR8 *)&pTcpa->Signature );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowDecimalValue ( SocketFD,
                               pPort,
                               "Length",
                               pTcpa->Length );
    if ( EFI_ERROR ( Status )) {
      break;
    }

    //
    //  Display the data from the table
    //
    Status = RowDump ( SocketFD,
                       pPort,
                       "Data",
                       pTcpa->Length - sizeof ( *pTcpa ) + 1,
                       (UINT8 *)( pTcpa + 1 ));
    if ( EFI_ERROR ( Status )) {
      break;
    }

    //
    //  Build the table trailer
    //
    Status = TableTrailer ( SocketFD,
                            pPort,
                            pbDone );
    break;
  }

  //
  //  Return the operation status
  //
  DBG_EXIT_STATUS ( Status );
  return Status;
}


/**
  Respond with the UEFI table

  @param [in] SocketFD      The socket's file descriptor to add to the list.
  @param [in] pPort         The WSDT_PORT structure address
  @param [out] pbDone       Address to receive the request completion status

  @retval EFI_SUCCESS       The request was successfully processed

**/
EFI_STATUS
AcpiUefiPage (
  IN int SocketFD,
  IN WSDT_PORT * pPort,
  OUT BOOLEAN * pbDone
  )
{
  CONST ACPI_UNKNOWN * pUefi;
  EFI_STATUS Status;

  DBG_ENTER ( );

  //
  //  Send the UEFI page
  //
  for ( ; ; ) {
    //
    //  Locate the UEFI
    //
    pUefi = (ACPI_UNKNOWN *)LocateTable ( UEFI_SIGNATURE );
    if ( NULL == pUefi ) {
      Status = EFI_NOT_FOUND;
      break;
    }

    //
    //  Send the page and table header
    //
    Status = TableHeader ( SocketFD, pPort, L"UEFI Table", pUefi );
    if ( EFI_ERROR ( Status )) {
      break;
    }

    //
    //  Display the header
    //
    Status = RowAnsiArray ( SocketFD,
                            pPort,
                            "Signature",
                            sizeof ( pUefi->Signature ),
                            (CHAR8 *)&pUefi->Signature );
    if ( EFI_ERROR ( Status )) {
      break;
    }
    Status = RowDecimalValue ( SocketFD,
                               pPort,
                               "Length",
                               pUefi->Length );
    if ( EFI_ERROR ( Status )) {
      break;
    }

    //
    //  Display the data from the table
    //
    Status = RowDump ( SocketFD,
                       pPort,
                       "Data",
                       pUefi->Length - sizeof ( *pUefi ) + 1,
                       (UINT8 *)( pUefi + 1 ));
    if ( EFI_ERROR ( Status )) {
      break;
    }

    //
    //  Build the table trailer
    //
    Status = TableTrailer ( SocketFD,
                            pPort,
                            pbDone );
    break;
  }

  //
  //  Return the operation status
  //
  DBG_EXIT_STATUS ( Status );
  return Status;
}
